class BitSet:
    set_DEFAULT = get_DEFAULT = -1
    set_CHANGE  = get_VALUE   =  0
    set_AND     = get_STR     =  1
    set_OR      = get_DETAIL  =  2
    def __init__(self, mask):
        if isinstance(mask, int) :
            self.lenth = mask
            self.names = []
        elif isinstance(mask, list) :
            if len(mask) != len(set(mask)) : raise ValueError("传入的list中不允许存在重复的元素")
            for i in mask :
                if isinstance(i, int) : raise ValueError("传入的list中不允许存在Int类型数据")
            self.lenth = len(mask)
            self.names = mask
        self.mask = pow(2, self.lenth)-1
        self.DATA = 0
    def __repr__(self):
        str_detail = "BitSet #%02d# <DATA>:[%s]" % (self.lenth, ("{:0>%db}"%self.lenth).format(self.DATA))
        if self.names != [] :
            str_detail += " = { "
            for i,name in enumerate(self.names) : str_detail += "<%s>:[%s] , "%(name, (self.DATA>>(self.lenth-i-1))&1)
            str_detail += "\b\b\b }"
        return str_detail
    def __call__(self, data=None, *, set_mode=-1, get_mode=-1):
        if isinstance(data, int) :
            if (data >= 0) & (data <= self.mask) :
                if   set_mode == BitSet.set_DEFAULT : self.DATA = data & self.mask
                elif set_mode == BitSet.set_CHANGE  : self.DATA = data & self.mask
                elif set_mode == BitSet.set_AND     : self.DATA &= data & self.mask
                elif set_mode == BitSet.set_OR      : self.DATA |= data & self.mask
            else : raise ValueError("输入的数据[%d]不在可被接受的范围[%d]~[%d]"%(data, 0, self.mask))
        if   get_mode == BitSet.get_DEFAULT :
            if data != None :                 return self
            else :                            return self.DATA
        elif get_mode == BitSet.get_VALUE   : return self.DATA
        elif get_mode == BitSet.get_STR     : return self.__str__()
        elif get_mode == BitSet.get_DETAIL  : return self.__repr__()
    def __getitem__(self, key):
        if not isinstance(key, (int, slice)) :
            if self.names == [] : raise KeyError("若想使用特殊索引，请使用无重复List初始化BitSet")
            elif key in self.names : key = self.names.index(key)
            else : raise KeyError("%s 不是一个正确索引,且不在初始化的List %s 中"%(key, self.names))
        if isinstance(key, int) :
            if (key >= self.lenth) | (key < -self.lenth) : 
                raise KeyError("超出设定的位数范围: %d(range: %d~%d)"%(key, -self.lenth, self.lenth-1))
        str_data = ("{:0>%db}"%self.lenth).format(self.DATA)
        return int("0"+str_data[key], 2)
    def __setitem__(self, key, value):
        if not isinstance(key, (int, slice)) :
            if self.names == [] : raise KeyError("若想使用特殊索引，请使用无重复List初始化BitSet")
            elif key in self.names : key = self.names.index(key)
            else : raise KeyError("%s 不是一个正确索引,且不在初始化的List %s 中"%(key, self.names))
        list_data = list(("{:0>%db}"%self.lenth).format(self.DATA))
        if isinstance(key, int) : 
            if (key >= self.lenth) | (key < -self.lenth) : 
                raise KeyError("超出设定的位数范围: %d(range: %d~%d)"%(key, -self.lenth, self.lenth-1))
            value_lenth = 1
            key = slice(key, key+1, 1)
        else :
            value_lenth = len(list_data[key])
        list_value = list(("{:0>%db}"%value_lenth).format(value))
        if len(list_value) > value_lenth : 
            raise ValueError("输入的数据位数不正确,需要%d位,传入为%d位:[%s]"%(value_lenth, len(list_value), "{:b}".format(value)))
        list_data[key] = list_value
        str_data = "".join(list_data)
        if len(str_data) != self.lenth : raise Exception("发生了未知错误,数据无法写入")
        self.DATA = int(str_data, 2)
    def __getattr__(self, attr):
        if attr in self.names : return self[attr]
        else : raise AttributeError("未找到对应位的数据,请在初始化时传入包含\"%s\"的List"%attr)
    def __setattr__(self, attr, value):
        if attr in ["lenth", "names", "mask", "DATA"] : self.__dict__[attr] = value
        elif attr in self.names :
            if value // 2 == 0 : self[attr] = value
            else : raise ValueError("输入的数据不正确,需要[0]或[1],传入数据为[%s]"%value)
        else : raise AttributeError("未找到对应位的数据,请在初始化时传入包含\"%s\"的List"%attr)
    def __str__(self):
        return ("{:0>%db}"%self.lenth).format(self.DATA)
    def __len__(self):
        return self.lenth

class Chip:
    @staticmethod
    def logic(chip):
        print(" # Chip使用帮助:")
        print(" # 重写 logic[@staticmethod] 来实现芯片的内部逻辑功能")
        print(" # ================================================")
        print(" # 使用Chip()来获取Chip输出的值")
        print(" # 使用Chip(data)来将data写入到Chip的输入")
        print(" # 使用Chip[]指定chip的引脚控制")
    def __init__(self, pinIN:BitSet, pinOUT:BitSet, delay:bool=False):
        self.pinIN = pinIN
        self.pinOUT = pinOUT
        self.lenth = pinIN.lenth + pinOUT.lenth
        self.delay = delay
    def __repr__(self):
        return "%s #%02d# <IN>:[%s] , <OUT>:[%s]"%(self.__class__.__name__, self.pinIN.lenth+self.pinOUT.lenth, self.pinIN, self.pinOUT)
    def __call__(self, input=None):
        if input == None : return self.pinOUT()
        if isinstance(input, int) : self.pinIN(input)
        if isinstance(input, (BitSet, Chip)) : self.pinIN(input())
        if isinstance(input, tuple) :
            data = ""
            for i in input : 
                if isinstance(i, int) : data += "{:b}".format(i)
                elif isinstance(i, str) : data += i
                elif isinstance(i, (BitSet, Chip)) : data += "%s"%i
            self.pinIN(int(data, 2))
        self.logic(self)
        return self
    def __str__(self):
        return str(self.pinIN) + str(self.pinOUT)
    def __getitem__(self, key):
        if isinstance(key, (int, slice)) :
            if isinstance(key, int) : key = slice(key, key+1)
            str_data = self.__str__()
            return int("0"+str_data[key], 2)
        else : raise KeyError("请使用数字获取引脚信息")
    def __setitem__(self, key, value):
        if isinstance(key, (int, slice)) :
            list_data = list(self.__str__()[:self.pinIN.lenth])
            if isinstance(key, int) :
                value_lenth = 1
                key = slice(key, key+1)
            else : value_lenth = len((" "*128)[key])
        else : raise KeyError("请使用数字或切片获取引脚信息")
        if isinstance(value, int) :
            list_value = list(("{:0>%db}"%value_lenth).format(value))
            if len(list_value) > value_lenth : 
                raise ValueError("输入的数据位数不正确,需要%d位,传入为%d位:[%s]"%(value_lenth, len(list_value), "{:b}".format(value)))
            list_data[key] = list_value
            self.pinIN(int("".join(list_data[:self.pinIN.lenth]), 2))
    def isinput(self, pin)->bool:
        if isinstance(pin, int) : pin = slice(pin, pin+1)
        elif isinstance(pin, slice) :
            if pin.start == None : pin.start = 0
            elif pin.start < 0 : pin.start += self.lenth
            if pin.stop == None : pin.stop = 0
            elif pin.stop < 0 : pin.stop += self.lenth
        return (pin.start != pin.stop) & (pin.start >= 0) & (pin.stop <= self.pinIN.lenth)
    def isoutput(self, pin)->bool:
        if isinstance(pin, int) : pin = slice(pin, pin+1)
        elif isinstance(pin, slice) :
            if pin.start == None : pin.start = 0
            elif pin.start < 0 : pin.start += self.lenth
            if pin.stop == None : pin.stop = 0
            elif pin.stop < 0 : pin.stop += self.lenth
        return (pin.start != pin.stop) & (pin.start >= self.pinIN.lenth) & (pin.stop <= self.lenth)
    def input(self, data):
        self.pinIN(data)
        if not self.delay : self.logic(self)
    def output(self):
        return self.pinOUT
    def update(self):
        self.logic(self)
    def show(self):
        print(self)

class Wire:
    def __init__(self, width=1):
        self.width = width
        self.output = []
        self.input  = []
        self.data = 0
    def __call__(self, chip, pin):
        self.link(chip, pin)
        return self
    def link(self, chip, pin):
        if isinstance(pin, slice) :
            width = len(str(chip)[pin])
            if width > self.width : raise ValueError("线缆连接的引脚数最大为[%d],当前连接引脚为[%d]"%(self.width, width))
        else : width = 1
        if isinstance(chip, Chip):
            if chip.isinput(pin) :
                if (chip, pin) not in self.input : self.input.append((chip, pin, width))
            elif chip.isoutput(pin) : 
                if (chip, pin) not in self.output : self.output.append((chip, pin, width))
            else : raise ValueError("pin[%s]不存在或不同属于in/out"%str(pin))
        elif isinstance(chip, BitSet):
            if (chip, pin) not in self.output : self.output.append((chip, pin, width))
    def update(self):
        self.data = 0
        for i in self.output : 
            self.data |= i[0][i[1]]
        for o in self.input :
            o[0][o[1]] = (self.data & (pow(2, o[2])-1))

